//#include "add_cast_engine_token_fuzzer.h"
#include "cast_engine_common.h"
//#include "cast_engine_common_helper.h"
#include "cast_engine_errors.h"
#include "cast_session_manager_service.h"
#include "accesstoken_kit.h"
#include "nativetoken_kit.h"
#include "token_setproc.h"
//#include "discovery_manager.h"
//#include "connection_manager.h"
#include <surface.h>
#include <consumer_surface.h>
#include <surface_utils.h>

//#include "media_errors.h"
//#include "directory_ex.h"
#include "ui/rs_surface_node.h"
#include "window.h"




using namespace OHOS;
using namespace OHOS::Rosen;
using namespace OHOS::Media;
using namespace OHOS::CastEngine;
using namespace OHOS::CastEngine::CastEngineService;

namespace OHOS {
namespace CastEngine {
namespace CastEngineService {
DEFINE_CAST_ENGINE_LABEL("dlna-SessionManagerServiceTest");
namespace {
enum {
    REGISTER_LISTENER = 0,
    UNREGISTER_LISTENER,
    RELEASE,
    SET_LOCAL_DEVICE,
    CREATE_CAST_SESSION,
    SET_SINK_SESSION_CAPACITY,
    START_DISCOVERY,
    SET_DISCOVERABLE,
    STOP_DISCOVERY,
    GET_CAST_SESSION
};
} // namespace

#if 1
sptr<CastSessionManagerService> gservice;
int32_t CastSessionManagerServiceStubOnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply)
{
    MessageOption option;
	CLOGE("CastSessionManagerServiceStubOnRemoteRequest, code:%{public}d", code);
	int32_t ret = gservice->OnRemoteRequest(code, data, reply, option);
	CLOGE("CastSessionManagerServiceStubOnRemoteRequest, ret:%{public}d", ret);
    return ret;
}

int32_t CastSessionManagerService_create()
{
	bool runOnCreate = true;
    gservice = new (std::nothrow) CastSessionManagerService(CAST_ENGINE_SA_ID, runOnCreate);
    if (!gservice) {
        CLOGE("CastSessionManagerService is null");
        return CAST_ENGINE_ERROR;
    }
	CLOGE("CastSessionManagerService_create, gservice");
	return 0;
}
#endif


int32_t UnregisterListenerFuzzTest(const uint8_t *data, size_t size)
{
    if ((data == nullptr) || (size == 0)) {
        return CAST_ENGINE_ERROR;
    }
    MessageParcel dataParcel;
    MessageParcel reply;
    if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) {
        return CAST_ENGINE_ERROR;
    }
    int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(UNREGISTER_LISTENER, dataParcel, reply);
    if (ret == ERR_UNKNOWN_TRANSACTION) {
        return ERR_NO_PERMISSION;
    } else if (ret != ERR_NONE) {
        return CAST_ENGINE_ERROR;
    }

    return reply.ReadInt32();
}

int32_t ReleaseFuzzTest(const uint8_t *data, size_t size)
{
    if ((data == nullptr) || (size == 0)) {
        return CAST_ENGINE_ERROR;
    }
    MessageParcel dataParcel;
    MessageParcel reply;
    if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) {
        return CAST_ENGINE_ERROR;
    }
    int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(RELEASE, dataParcel, reply);
    if (ret == ERR_UNKNOWN_TRANSACTION) {
        return ERR_NO_PERMISSION;
    } else if (ret != ERR_NONE) {
        return CAST_ENGINE_ERROR;
    }

    return reply.ReadInt32();
}

int32_t SetSinkSessionCapacityFuzzTest(const uint8_t *data, size_t size)
{
    if ((data == nullptr) || (size < sizeof(int32_t))) {
        return CAST_ENGINE_ERROR;
    }
    int32_t sessionCapacity = *reinterpret_cast<const int32_t *>(data);
    MessageParcel dataParcel;
    MessageParcel reply;
    if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) {
        return CAST_ENGINE_ERROR;
    }
    if (!dataParcel.WriteInt32(sessionCapacity)) {
        return CAST_ENGINE_ERROR;
    }
    int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(SET_SINK_SESSION_CAPACITY, dataParcel, reply);
    if (ret == ERR_UNKNOWN_TRANSACTION) {
        return ERR_NO_PERMISSION;
    } else if (ret != ERR_NONE) {
        return CAST_ENGINE_ERROR;
    }

    return reply.ReadInt32();
}

int32_t StartDiscoveryFuzzTest(const uint8_t *data, size_t size)
{
    if ((data == nullptr) || (size < sizeof(int32_t))) {
        return CAST_ENGINE_ERROR;
    }
	CLOGE("protocol type comes, %{public}d, %{public}d, %{public}d, %{public}d", data[0], data[1], data[2], data[3]);
    int32_t protocols = *reinterpret_cast<const int32_t *>(data);
    MessageParcel dataParcel;
    MessageParcel reply;
    if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) {
        return CAST_ENGINE_ERROR;
    }
	CLOGE("protocol type comes, %{public}d", protocols);
    if (!dataParcel.WriteInt32(protocols)) {
        return CAST_ENGINE_ERROR;
    }
	CLOGE("%s, %d", __FUNCTION__, __LINE__);
    int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(START_DISCOVERY, dataParcel, reply);
	CLOGE("%s, %d", __FUNCTION__, __LINE__);
    if (ret == ERR_UNKNOWN_TRANSACTION) {
        return ERR_NO_PERMISSION;
    } else if (ret == ERR_INVALID_DATA) {
        return ERR_INVALID_PARAM;
    } else if (ret != ERR_NONE) {
        return CAST_ENGINE_ERROR;
    }
	CLOGE("%s, %d", __FUNCTION__, __LINE__);
    return reply.ReadInt32();
}

int32_t SetDiscoverableFuzzTest(bool enable)
{
    MessageParcel dataParcel;
    MessageParcel reply;
	CLOGE("SetDiscoverableFuzzTest start");
    if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) {
        return CAST_ENGINE_ERROR;
    }
    if (!dataParcel.WriteBool(enable)) {
        return CAST_ENGINE_ERROR;
    }
	CLOGE("SetDiscoverableFuzzTest");
    int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(SET_DISCOVERABLE, dataParcel, reply);
    if (ret == ERR_UNKNOWN_TRANSACTION) {
        return ERR_NO_PERMISSION;
    } else if (ret != ERR_NONE) {
        return CAST_ENGINE_ERROR;
    }

    return reply.ReadInt32();
}

int32_t StopDiscoveryFuzzTest(const uint8_t *data, size_t size)
{
    if ((data == nullptr) || (size == 0)) {
        return CAST_ENGINE_ERROR;
    }
    MessageParcel dataParcel;
    MessageParcel reply;
    if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) {
        return CAST_ENGINE_ERROR;
    }
    int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(STOP_DISCOVERY, dataParcel, reply);
    if (ret == ERR_UNKNOWN_TRANSACTION) {
        return ERR_NO_PERMISSION;
    } else if (ret != ERR_NONE) {
        return CAST_ENGINE_ERROR;
    }

    return reply.ReadInt32();
}

int32_t GetCastSessionFuzzTest(const uint8_t *data, size_t size)
{
    if ((data == nullptr) || (size == 0)) {
        return CAST_ENGINE_ERROR;
    }
    MessageParcel dataParcel;
    MessageParcel reply;
    std::string sessionId(reinterpret_cast<const char *>(data), size);
    if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) {
        return CAST_ENGINE_ERROR;
    }
    if (!dataParcel.WriteString(sessionId)) {
        return CAST_ENGINE_ERROR;
    }
    if (CastSessionManagerServiceStubOnRemoteRequest(GET_CAST_SESSION, dataParcel, reply) != ERR_NONE) {
        return CAST_ENGINE_ERROR;
    }
    auto object = reply.ReadRemoteObject();
    if (object == nullptr) {
        return CAST_ENGINE_ERROR;
    }

    return reply.ReadInt32();
}

void token_permission()
{
	int ret = -1;
	CLOGE("token_permission start");
	constexpr int castPermissionNum = 10;
    const char *perms[castPermissionNum] = {
        "ohos.permission.ACCESS_CAST_ENGINE_MIRROR",
        "ohos.permission.ACCESS_CAST_ENGINE_STREAM",
        "ohos.permission.DISTRIBUTED_DATASYNC",
		"ohos.permission.ACCESS_SERVICE_DM",
		"ohos.permission.ABILITY_BACKGROUND_COMMUNICATION",
		"ohos.permission.GET_RUNNING_INFO",
		"ohos.permission.MEDIA_LOCATION",
		"ohos.permission.WRITE_MEDIA",
		"ohos.permission.READ_MEDIA",
		"ohos.permission.INTERNET",
    };
    NativeTokenInfoParams infoInstance = {
        .dcapsNum = 0,  // Indicates the capsbility list of the sa.
        .permsNum = castPermissionNum,
        .aclsNum = 0,   // acls is the list of rights that can be escalated.
        .dcaps = nullptr,
        .perms = perms,
        .acls = nullptr,
        .processName = "dlna_session_manager_service_test",
        .aplStr = "system_basic",
    };
    uint64_t tokenId = GetAccessTokenId(&infoInstance);
    CLOGE("tokenId is %lld", tokenId);
    SetSelfTokenID(tokenId);
    ret = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo();
	if (ret != 0) {
        CLOGE("ReloadNativeTokenInfo failed");
        return;
    }
}

class BufferConsumerListener : public ::OHOS::IBufferConsumerListener {
public:
    void OnBufferAvailable() override {CLOGE("enter");}
    void OnTunnelHandleChange() override {CLOGE("enter");}
    void OnGoBackground() override {CLOGE("enter");}
    void OnCleanCache() override {CLOGE("enter");}	
};


std::string CreateSurfaceId()
{
    sptr<IConsumerSurface> consSurface;
    sptr<IBufferProducer> producer;
    sptr<Surface> prodSurface;
    consSurface = IConsumerSurface::Create();
    if (!consSurface) {
        return "";
    }
    sptr<IBufferConsumerListener> surfaceListener = new BufferConsumerListener();
    if (!surfaceListener) {
        return "";
    }
    auto result = consSurface->RegisterConsumerListener(surfaceListener);
    if (!result) {
        return "";
    }
    producer = consSurface->GetProducer();
    if (!producer) {
        return "";
    }
    prodSurface = Surface::CreateSurfaceAsProducer(producer);
    if (!prodSurface) {
        return "";
    }
    SurfaceUtils::GetInstance()->Add(prodSurface->GetUniqueId(), prodSurface);
    auto uniqueId = prodSurface->GetUniqueId();
    std::string surfaceId = std::to_string(uniqueId);
    return surfaceId;
}


#if 0
using namespace OHOS::DistributedHardware;
class TestDiscoveryManagerListener : public IDiscoveryManagerListener {
	public:
		void OnDeviceFound(const std::vector<CastInnerRemoteDevice> &devices) override
		{
			 CLOGE("TestDiscoveryManagerListener OnDeviceFound");
		}
};	
class TestConnectionManagerListener : public IConnectionManagerListener {
	public:
		int NotifySessionIsReady() override
		{
			CLOGE("TestConnectionManagerListener NotifySessionIsReady");
			return 0;
		}
	
		bool NotifyRemoteDeviceIsReady(int castSessionId, const CastInnerRemoteDevice &device) override
		{
			CLOGE("TestConnectionManagerListener NotifyRemoteDeviceIsReady");
			return true;
		}
	
		void NotifyDeviceIsOffline(const std::string &deviceId) override
		{
			CLOGE("TestConnectionManagerListener NotifyDeviceIsOffline");
		}
	
		void OnError(const std::string &deviceId) override
		{
			CLOGE("TestConnectionManagerListener OnError");
		}
};
#endif
} // namespace CastEngineService
} // namespace CastEngine
} // namespace OHOS

class TestCastServiceListenerImpl : public IRemoteStub<ICastServiceListenerImpl> {
public:
    virtual void OnDeviceFound(const std::vector<CastRemoteDevice> &deviceList) override {}
    virtual void OnDeviceOffline(const std::string &deviceId) override {}
    virtual void OnSessionCreated(const sptr<ICastSessionImpl> &castSession) override {}
    virtual void OnServiceDied() override {}
};

class TestStreamPlayerImpl : public IRemoteStub<IStreamPlayerImpl> {

};

class TestStreamPlayerListener : public IRemoteStub<IStreamPlayerListenerImpl> {
public:
    void OnStateChanged(const PlayerStates playbackState, bool isPlayWhenReady) override {CLOGE("start");}
    void OnPositionChanged(int position, int bufferPosition, int duration) override {CLOGE("start");}
    void OnMediaItemChanged(const MediaInfo &mediaInfo) override {CLOGE("start");}
    void OnVolumeChanged(int volume, int maxVolume) override {CLOGE("start");}
    void OnLoopModeChanged(const LoopMode loopMode) override {CLOGE("start");}
    void OnPlaySpeedChanged(const PlaybackSpeed speed) override {CLOGE("start");}
    void OnPlayerError(int errorCode, const std::string &errorMsg) override {CLOGE("start");}
    void OnVideoSizeChanged(int width, int height) override {CLOGE("start");}
    void OnNextRequest() override {CLOGE("start");}
    void OnPreviousRequest() override {CLOGE("start");}
    void OnSeekDone(int position) override {CLOGE("start");}
    void OnEndOfStream(int isLooping) override{CLOGE("start");}
};

sptr<Surface> GetSubWindowSurface()
{
    sptr<Rosen::WindowOption> option = new Rosen::WindowOption();
    option->SetWindowRect({ 0, 0, 1920, 1080 });
    option->SetWindowType(Rosen::WindowType::WINDOW_TYPE_APP_LAUNCHING);
    option->SetWindowMode(Rosen::WindowMode::WINDOW_MODE_FLOATING);

	sptr<Rosen::Window> previewWindow_ = Rosen::Window::Create("xcomponent_window", option);
    if (previewWindow_ == nullptr || previewWindow_->GetSurfaceNode() == nullptr) {
        CLOGE("GetSubWindowSurface is fail");
        return nullptr;
    }
	
    previewWindow_->Show();
	
    std::shared_ptr<OHOS::Rosen::RSSurfaceNode> surfaceNode = previewWindow_->GetSurfaceNode();
    surfaceNode->SetFrameGravity(Rosen::Gravity::RESIZE);

    //Rosen::RSTransaction::FlushImplicitTransaction();
    return surfaceNode->GetSurface();
}

int main()
{
	int ret = 0;

    token_permission();	
	
	CastSessionManagerService_create();

	CLOGE("register start");
	sptr<ICastSessionImpl> castSession;
	sptr<TestCastServiceListenerImpl> cast_service_listener = new (std::nothrow) TestCastServiceListenerImpl();
	gservice->RegisterListener(cast_service_listener);
	gservice->CreateCastSession(CastSessionProperty {}, castSession);

	sptr<IStreamPlayerImpl> streamPlayer;
	castSession->CreateStreamPlayer(streamPlayer);
	sptr<IStreamPlayerListenerImpl> listenerStub = new (std::nothrow) TestStreamPlayerListener();
	streamPlayer->RegisterListener(listenerStub);
	if (ret != 0) {
		CLOGE("streamPlayManager->RegisterListener failed");
		return -1;
	}
	
	sptr<Surface> producerSurface = nullptr;
	producerSurface = GetSubWindowSurface();
	producerSurface->SetUserData("SURFACE_FORMAT", std::to_string(12));
	ret = streamPlayer->SetSurface_ext(producerSurface);	//sptr<IBufferProducer> producer
	if (ret != 0) {
        CLOGE("SetSurface failed");
        return -1;
	}
	CLOGE("register end");

	#if 0
	CLOGE("SetDiscoverableFuzzTest start");
    ret = SetDiscoverableFuzzTest(true);
	if (ret != 0) {
        CLOGE("SetDiscoverableFuzzTest failed");
        return -1;
    }
	CLOGE("SetDiscoverableFuzzTest succes");
	#endif

	while(1)
	{
		sleep(1);
	}
}


